package com.bocai.grainshop.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.bocai.common.constant.CartConstant;
import com.bocai.common.utils.R;
import com.bocai.grainshop.cart.feigin.OrderFeignService;
import com.bocai.grainshop.cart.feigin.ProductFeignService;
import com.bocai.grainshop.cart.interceptor.UserInterceptor;
import com.bocai.grainshop.cart.service.CartService;
import com.bocai.grainshop.cart.to.UserInfoTo;
import com.bocai.grainshop.cart.vo.CartItemVo;
import com.bocai.grainshop.cart.vo.CartVo;
import com.bocai.grainshop.cart.vo.SkuInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService{

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public CartItemVo addToCart(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> ops = getOps();

        //判断redis中有无此商品
        String res = (String) ops.get(skuId.toString());
        if(!StringUtils.hasText(res)){
            CartItemVo cartItemVo = new CartItemVo();
            //第一个异步任务  远程查询 skuid信息
            CompletableFuture<Void> inforunAsync = CompletableFuture.runAsync(() -> {
                R info = productFeignService.info(skuId);
                Object code = info.get("code");
                String jsonString = JSON.toJSONString(code);
                Integer codeNum = JSON.parseObject(jsonString, new TypeReference<Integer>() {
                });
                if (codeNum == 0) {
                    Object skuInfo = info.get("skuInfo");
                    if (skuInfo != null) {
                        String s = JSON.toJSONString(skuInfo);
                        SkuInfoVo skuInfoVo = JSON.parseObject(s, SkuInfoVo.class);
                        //封装购物车详情
                        cartItemVo.setCheck(true);
                        cartItemVo.setImage(skuInfoVo.getSkuDefaultImg());
                        cartItemVo.setTitle(skuInfoVo.getSkuTitle());
                        cartItemVo.setPrice(skuInfoVo.getPrice());
                        cartItemVo.setSkuId(skuId);
                        cartItemVo.setCount(num);
                    }
                }
            }, threadPoolExecutor);

            //不关心返回值  异步查询sku的销售属性
            CompletableFuture<Void> salarunAsync = CompletableFuture.runAsync(() -> {
                List<String> salaAttrToString = productFeignService.getSalaAttrToString(skuId);
                cartItemVo.setSkuAttrValues(salaAttrToString);
            }, threadPoolExecutor);

            //等两个异常任务都完成
            try {
                CompletableFuture.allOf(salarunAsync,inforunAsync).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }

            //存redis redis会序列化对象（默认 jdk的序列化） 防止不能拿到数据 提前转成json
            String cartItemJson = JSON.toJSONString(cartItemVo);

            ops.put(skuId.toString(),cartItemJson);

            return cartItemVo;
        }else {
            //如果有改数量
            CartItemVo cartItemVo = JSON.parseObject(res, CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount()+num);
            //存redis redis会序列化对象（默认 jdk的序列化） 防止不能拿到数据 提前转成json
            String cartItemJson = JSON.toJSONString(cartItemVo);
            ops.delete(skuId.toString());
            ops.put(skuId.toString(),cartItemJson);
            return cartItemVo;
        }
    }

    @Override
    public CartItemVo getItemMessage(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        String o = (String) ops.get(skuId.toString());
        CartItemVo cartItemVo = JSON.parseObject(o, CartItemVo.class);
        return cartItemVo;
    }

    @Override
    public CartVo getCart() {
        UserInfoTo userInfoTo = UserInterceptor.threadLocal.get();
        CartVo cartVo = new CartVo();
        if(userInfoTo.getUserId()!=null){
            //登录过
            String user_key = CartConstant.CART_PREFIX + userInfoTo.getUserId();
            List<CartItemVo> cartByUserKey = getCartByUser_key(CartConstant.CART_PREFIX + userInfoTo.getUserKey());
            if(cartByUserKey!=null){
                //临时购物车有东西  合并购物车
                for (CartItemVo cartItemVo : cartByUserKey) {
                    addToCart(cartItemVo.getSkuId(),cartItemVo.getCount());
                }
                //合并清空临时购物车
                redisTemplate.delete(CartConstant.CART_PREFIX + userInfoTo.getUserKey());
            }
            List<CartItemVo> cartByUser_key = getCartByUser_key(user_key);
            cartVo.setItems(cartByUser_key);
        }else {
            //临时购物车
            String user_key = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
            List<CartItemVo> cartByUser_key = getCartByUser_key(user_key);
            cartVo.setItems(cartByUser_key);
        }
        return cartVo;
    }

    @Override
    public void checkItem(Long skuId, Integer checked) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        Object o = ops.get(skuId.toString());
        CartItemVo cartItemVo = JSON.parseObject((String) o, CartItemVo.class);
        assert cartItemVo != null;
        cartItemVo.setCheck(checked==1?true:false);
        ops.delete(skuId.toString());
        ops.put(skuId.toString(),JSON.toJSONString(cartItemVo));
    }

    @Override
    public void countItem(Long skuId, Integer num) {
        //获取需要操作的购物车  以判断登录
        BoundHashOperations<String, Object, Object> ops = getOps();
        //获取原始skuId对应的数据
        String o = (String) ops.get(skuId.toString());
        //转为对象
        CartItemVo cartItemVo = JSON.parseObject(o, CartItemVo.class);
        //修改内容  数量
        assert cartItemVo != null;
        cartItemVo.setCount(num);
        //删除原来的内容
        ops.delete(skuId.toString());
        //存入新数据
        ops.put(skuId.toString(),JSON.toJSONString(cartItemVo));
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        ops.delete(skuId.toString());
    }

    /**
     * @Author: SunJinbo
     * @Description  远程方法获取用户结算的购物车的购物项信息
     * @Param []
     * @return java.util.List<com.bocai.grainshop.cart.vo.CartItemVo>
     * @Data Created in 2022/4/21 17:17
     */
    @Override
    public List<CartItemVo> getUserCartItems() {
        UserInfoTo userInfoTo = UserInterceptor.threadLocal.get();
        if(userInfoTo.getUserId() == null){
            //没有登录过的
            return null;
        }else {
            //登录过的
            String user_key = CartConstant.CART_PREFIX + userInfoTo.getUserId();
            //获取出购物项信息集合
            List<CartItemVo> cartByUser_key = getCartByUser_key(user_key);
            //过滤出被选中的购物项
            List<CartItemVo> collect = cartByUser_key.stream().filter((item)
                    -> item.getCheck() == true).map((item)->{
                 //价格不能使用缓存的需要实时查询数据库的真实价格
                R r = productFeignService.getPriceBySkuId(item.getSkuId());

                Object code = r.get("code");
                String s = JSON.toJSONString(code);
                Integer codeNum = JSON.parseObject(s, new TypeReference<Integer>() {
                });
                if(codeNum == 0){
                    Object price = r.get("price");
                    String priceJSON = JSON.toJSONString(price);
                    BigDecimal priceBig = JSON.parseObject(priceJSON, new TypeReference<BigDecimal>() {
                    });
                    if(priceBig != null){
                        item.setPrice(priceBig);
                    }
                }
                return item;
            }).collect(Collectors.toList());
            return collect;
        }
    }

    @Autowired
    private OrderFeignService orderFeignService;

    /**
     * @Author: SunJinbo
     * @Description  支付成功后修改购物车内容
     * @Param []
     * @return void
     * @Data Created in 2022/5/4 20:16
     */
    @Override
    public void updateCartItems() {
        UserInfoTo userInfoTo = UserInterceptor.threadLocal.get();
        if(userInfoTo.getUserId() != null){
            String user_key = CartConstant.CART_PREFIX + userInfoTo.getUserId();
            BoundHashOperations<String, String, String> ops = redisTemplate.boundHashOps(user_key);
            //查询数据库订单已支付的订单
            R array = orderFeignService.getFinshOrderSkuArray();
            Object code = array.get("code");
            String s = JSON.toJSONString(code);
            Integer codeNum = JSON.parseObject(s, new TypeReference<Integer>() {
            });
            if(codeNum == 0){
                Object o = array.get("array");
                String toJSONString = JSON.toJSONString(o);
                List<Long> list = JSON.parseObject(toJSONString, new TypeReference<List<Long>>() {
                });
                if(list.size() > 0 && list != null){
                    for (Long i : list) {
                        String value = ops.get(i.toString());
                        if(value != null){
                            CartItemVo cartItemVo = JSON.parseObject(value, CartItemVo.class);
                            if(cartItemVo.getCount() >= 2){
                                cartItemVo.setCount(cartItemVo.getCount() - 1);
                                ops.delete(i.toString());
                                ops.put(i.toString(),JSON.toJSONString(cartItemVo));
                            }else {
                                ops.delete(i.toString());
                            }
                        }
                    }
                }
            }
        }else {
            throw new RuntimeException();
        }
    }

    /**
     * @Author: SunJinbo
     * @Description  从redis获取我们要操作的购物车
     * @Param []
     * @return org.springframework.data.redis.core.BoundHashOperations<java.lang.String,java.lang.Object,java.lang.Object>      
     * @Data Created in 2022/4/17 16:53
     */
    public BoundHashOperations<String, Object, Object> getOps(){
        UserInfoTo userInfoTo = UserInterceptor.threadLocal.get();
        String use_key = "";
        if(userInfoTo.getUserId()!=null){
            use_key = CartConstant.CART_PREFIX +userInfoTo.getUserId();
        }else {
            use_key = CartConstant.CART_PREFIX +userInfoTo.getUserKey();
        }
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(use_key);
        return operations;
    }

    /**
     * @Author: SunJinbo
     * @Description  通过key获取购物车的hash操作
     * @Param []
     * @return java.util.List<com.bocai.grainshop.cart.vo.CartItemVo>
     * @Data Created in 2022/4/18 19:23
     */
    public List<CartItemVo> getCartByUser_key(String user_key){
        BoundHashOperations<String, Object, Object> hashOperations = redisTemplate.boundHashOps(user_key);
        List<Object> values = hashOperations.values();
        if(values!=null && values.size()>0){
            List<CartItemVo> collect = values.stream().map((obj) -> {
                CartItemVo cartItemVo = JSON.parseObject((String) obj, CartItemVo.class);
                return cartItemVo;
            }).collect(Collectors.toList());
           return collect;
        }
        return null;
    }

}
